﻿using System;
using System.Collections.Generic;
using System.Linq;

using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.Common.Locator;
using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.BusinessService;

using Fuse8.ContentManagementFramework.SystemFacade.Workflow;
using Fuse8.ContentManagementFramework.SystemFacade.Extensions;
using Fuse8.ContentManagementFramework.BizFacade.Services;
using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Bases;

namespace Fuse8.ContentManagementFramework.BizFacade.Workflow
{
    internal class WorkflowStorageService<TEntity, TKey> : ICmsWorkflowStorageService<TEntity, TKey>
        where TEntity: class, IWorkflowEntityObject<TKey>
        where TKey : IComparable<TKey>, IEquatable<TKey>
    {
        private readonly IEntityBusinessService<CmsWorkflow, Guid> _workflowService = new BusinessServiceFacade<CmsWorkflow, Guid>();
        private readonly IEntityBusinessService<CmsWorkflowHistory, int> _workflowHistoryService = new BusinessServiceFacade<CmsWorkflowHistory, int>();     

        #region ICmsWorkflowStorageService Members

        public void Create(TEntity entity, DateTime? approvalDeadline, DateTime? reviewDeadline)
        {
            Guard.ArgumentNotNull(entity, "entity");

            if (!entity.WorkflowId.HasValue)
            {
                CmsWorkflow workflowData = new CmsWorkflow
                {
                    Cycle = 1,
                    ApproveDateDeadline = approvalDeadline,
                    ReviewDateDeadline = reviewDeadline
                };

                _workflowService.Add(workflowData);

                entity.WorkflowId = workflowData.Id;
            }
        }

        public CmsWorkflowState Load(TEntity entity, IEnumerable<CmsWorkflowState> allWorkflowStates)
        {
            Guard.ArgumentNotNull(entity, "entity");

            CmsWorkflowState result = null;

            if (entity.WorkflowId.HasValue)
            {
                var data = _workflowService.FindOne(entity.WorkflowId.Value);
                if (data != null)
                {
                    var workflowState = data.LatestWorkflowState;
                    if (workflowState != null)
                    {
                        result = allWorkflowStates.FirstOrDefault(p => p.StateId == workflowState.WorkflowState);
                        if (result != null)
                        {
                            result.UserGroupId = workflowState.UserGroupId;
                            result.UserId = workflowState.UserId;
                            result.Notes = workflowState.Notes;

                            var additionalInformationType = !string.IsNullOrWhiteSpace(workflowState.WorkflowDataType) ?
                                Type.GetType(workflowState.WorkflowDataType, true, true) :
                                null;

                            if (additionalInformationType != null)
                            {
                                result.AdditionalInformation = workflowState.WorkflowData.DigUpFromString(additionalInformationType);
                            }
                        }
                    }
                }
            }

            return result;
        }

        public void Save(TEntity entity, CmsWorkflowState workflowState)
        {
            Guard.ArgumentNotNull(entity, "entity");
            Guard.ArgumentNotNull(workflowState, "workflowState");

            if (entity.WorkflowId.HasValue)
            {
                var workflowData = _workflowService .FindOne(entity.WorkflowId.Value);

                if (workflowData != null)
                {
                    var currentState = workflowData.LatestWorkflowState;

                    if ((currentState == null) || ((currentState != null) && (currentState.WorkflowState != workflowState.StateId)))
                    {
                        var additionalInformationType = !string.IsNullOrWhiteSpace(workflowState.AdditionalInformationType) ?
                            Type.GetType(workflowState.AdditionalInformationType, true, true) :
                            null;

                        var workflowHistoryData = new CmsWorkflowHistory
                        {
                            WorkflowId = entity.WorkflowId.Value,
                            UserGroupId = workflowState.UserGroupId,
                            UserId = workflowState.UserId,
                            WorkflowState = workflowState.StateId,
                            IsLatestState = true,
                            Notes = workflowState.Notes,
                            WorkflowDataType = workflowState.AdditionalInformationType,
                            WorkflowData = additionalInformationType != null ?
                                workflowState.AdditionalInformation.StoreMe(additionalInformationType) :
                                null
                        };

                        _workflowHistoryService.Add(workflowHistoryData);
                    }
                }
            }

            entity.IsLatestCompletedRevision = workflowState.IsFinalState;
        }

        public void Delete(TEntity entity)
        {
            Guard.ArgumentNotNull(entity, "entity");

            entity.WorkflowId = null;
            entity.IsLatestCompletedRevision = false;
        }

        #endregion
    }
}
